using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Media;

namespace WozLib.UI.Util
{
  public class HlsConverter
  {
        public static Color ConvertFromHls(HlsValue value){
          return ConvertFromHls(value.Hue, value.Lightness, value.Saturation);
        }

    /// <summary>
    /// Converts a hls value to a Color.
    /// </summary>
    /// <param name="h">The hue, H, of the new color (from 0 to 1).</param>
    /// <param name="l">The lightness, L, of the new color (from 0 to 1).</param>
    /// <param name="s">The saturation, S, of the new color (from 0 to 1).</param>
    public static Color ConvertFromHls(Double h, Double l, Double s) {
        Double p1;
        Double p2;

        Double r;
        Double g;
        Double b;

        h *= 360;

        if (l <= 0.5){
            p2 = l * (1 + s);
        }
        else {
            p2 = l + s - l * s;
        }

        p1 = 2 * l - p2;
        if (s == 0) {
            r = l;
            g = l;
            b = l;
        }
        else {
            r = QqhToRgb(p1, p2, h + 120);
            g = QqhToRgb(p1, p2, h);
            b = QqhToRgb(p1, p2, h - 120);
        }

        r *= Byte.MaxValue;
        g *= Byte.MaxValue;
        b *= Byte.MaxValue;

        return Color.FromRgb((byte)r, (byte)g, (byte)b);
  }

    private static double QqhToRgb(double q1, double q2, double hue){
        if (hue > 360) {
            hue = hue - 360;
        }
        else if (hue < 0) {
            hue = hue + 360;
        }

        if (hue < 60) {
            return q1 + (q2 - q1) * hue / 60.0;
        }
        else if (hue < 180) {
          return q2;
        }
        else if (hue < 240) {
          return q1 + (q2 - q1) * (240 - hue) / 60.0;
        }
        else {
          return q1;
        }
    }

    /// <summary>
    /// Converts a color to a HlsValue.
    /// </summary>
    /// <param name="color">The color to convert.</param>
    public static HlsValue ConvertToHls(Color color){
        Double max;
        Double min;
        Double diff;
        Double r_dist;
        Double g_dist;
        Double b_dist;

        Double R;
        Double G;
        Double B;

        Double h;
        Double l;
        Double s;

      double ByteMaxValue = Byte.MaxValue;
      R = color.R / ByteMaxValue;
      G = color.G / ByteMaxValue;
      B = color.B / ByteMaxValue;

        max = R;
        if ( max < G ) max = G;
        if ( max < B ) max = B;

        min = R;
        if ( min > G ) min = G;
        if ( min > B ) min = B;

        diff = max - min;
        l = (max + min) / 2.0;
        if (Math.Abs(diff) < 0.00001) {
            s = 0;
            h = 0;
        }
        else {
            if (l <= 0.5) {
                s = diff / (max + min);
            }
            else {
                s = diff / (2 - max - min);
            }

            r_dist = (max - R) / diff;
            g_dist = (max - G) / diff;
            b_dist = (max - B) / diff;

            if (R == max) {
                h = b_dist - g_dist;
            }
            else if (G == max) {
                h = 2 + r_dist - b_dist;
            }
            else {
                h = 4 + g_dist - r_dist;
            }

            h = h * 60;
            if (h < 0) h = h + 360;
        }

        h /= 360;
        return new HlsValue(h, l, s);
    }
  }

  public struct HlsValue
  {
    private double mHue;
    private double mLightness;
    private double mSaturation;

    public HlsValue(double h, double l, double s)
    {
      mHue = h;
      mLightness = l;
      mSaturation = s;
    }

    public double Hue
    {
      get
      {
        return mHue;
      }
      set
      {
        mHue = value;
      }
    }

    public double Lightness
    {
      get
      {
        return mLightness;
      }
      set
      {
        mLightness = value;
      }
    }

    public double Saturation
    {
      get
      {
        return mSaturation;
      }
      set
      {
        mSaturation = value;
      }
    }

    public static bool operator !=(HlsValue left, HlsValue right)
    {
      bool bool1;

      bool1 = left.Lightness != right.Lightness || left.Saturation != right.Saturation;

      if (!bool1)
      {
        return left.Hue != right.Hue && (left.Hue > 0 && right.Hue < 1) && (left.Hue < 1 && right.Hue > 0);
      }
      else
      {
        return bool1;
      }
    }

    public static bool operator ==(HlsValue left, HlsValue right)
    {
      bool bool1;

      bool1 = left.Lightness == right.Lightness && left.Saturation == right.Saturation;

      if (bool1)
      {
        return Math.Round(left.Hue, 2) == Math.Round(right.Hue, 2) || (Math.Round(left.Hue, 2) == 1 &&
          Math.Round(right.Hue, 2) == 0) || (Math.Round(left.Hue, 2) == 0 && Math.Round(right.Hue, 2) == 1);
      }
      else
      {
        return false;
      }
    }

    public override string ToString()
    {
      return String.Format("H: {0:0.00} L: {1:0.00} S: {2:0.00}", Hue, Lightness, Saturation);
    }
  }
}
